﻿using Clancy.Common.Extensions;
using Clancy.Interfaces;
using Clancy.Ui.Properties;
using ReactiveUI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using System.Windows;

namespace Clancy.Ui.ViewModels
{
    public class RecordingArchiveViewModel : ClancyEditorViewModelBase
    {
        protected readonly ObservableCollection<IRecording> RecordingsObservableCollection = new ObservableCollection<IRecording>();
        private readonly BehaviorSubject<RecordingThumbnailViewModel> m_SelectedRecordingBehaviorSubject = new BehaviorSubject<RecordingThumbnailViewModel>(null);
        private readonly ISelectionManager m_SelectionManager;
        private IReactiveDerivedList<RecordingThumbnailViewModel> m_RecordingViewModels;
        private ObservableAsPropertyHelper<RecordingThumbnailViewModel> m_SelectedRecordingViewModelHelper;

        public RecordingArchiveViewModel(IOperationalAdapterProvider operationalAdapterProvider, ISelectionManager selectionManager, ISurveilanceStorage surveilanceStorage)
            : base(operationalAdapterProvider, surveilanceStorage)
        {
            m_SelectionManager = selectionManager;
            CreateProperies();

            CreateRecordingArchiveCommands();

            FillRibbonCommands();

            RefreshOperationsAdapter();
        }

        public ReactiveCommand<object> CmdDeleteSelectedRecording { get; private set; }

        public ReactiveCommand<object> CmdRefreshRecordings { get; private set; }

        public ReactiveCommand<object> CmdViewSelectedRecording { get; private set; }

        public virtual IReactiveDerivedList<RecordingThumbnailViewModel> Recordings
        {
            get { return m_RecordingViewModels; }
        }

        public IRecording SelectedRecording
        {
            get
            {
                if (SelectedRecordingThumbnailDisplayObject == null)
                    return null;
                return SelectedRecordingThumbnailDisplayObject.Recording;
            }
        }

        public RecordingThumbnailViewModel SelectedRecordingThumbnailDisplayObject
        {
            get { return m_SelectedRecordingBehaviorSubject.Value; }
            set { m_SelectedRecordingBehaviorSubject.OnNext(value); }
        }

        protected override void DisposeElements()
        {
            IEnumerable<IDisposable> dispos = new[]
            {
                m_SelectedRecordingViewModelHelper
            };
            DisposeMultipleElements(dispos.ToList());
        }

        protected override void RefreshOperationsAdapter()
        {
            base.RefreshOperationsAdapter();

            RecordingsObservableCollection.Clear();

            AttachRecordingCollection();

            FillRecordingBufferWithCurrentValues();
        }

        private void AddRecordingsToDisplayBuffer(IList items)
        {
            foreach (IRecording recording in items.Cast<IRecording>().Where(recording => recording != null))
            {
                RecordingsObservableCollection.Add(recording);
            }
        }

        private void AttachRecordingCollection()
        {
            AttachToCollection(OperationAdapter.RecordingCollection,
                items => AddRecordingsToDisplayBuffer(items as IList),
                items => RemoveRecordingsToDisplayBuffer(items as IList));
        }

        private void CreateProperies()
        {
            m_SelectedRecordingViewModelHelper =
                new ObservableAsPropertyHelper<RecordingThumbnailViewModel>(m_SelectedRecordingBehaviorSubject,
                    _ =>
                    {
                        m_SelectionManager.SetSelection(SelectedRecording);
                        this.RaisePropertyChanged("SelectedRecordingThumbnailDisplayObject");
                        this.RaisePropertyChanged("SelectedRecording");
                    });

            m_RecordingViewModels = RecordingsObservableCollection.CreateDerivedCollection(recording =>
            {
                RecordingThumbnailViewModel recordingThumbnailViewModel = new RecordingThumbnailViewModel(recording);
                return recordingThumbnailViewModel;
            });
            DisposableRxElements.Add(m_RecordingViewModels);
        }

        private void CreateRecordingArchiveCommands()
        {
            CmdRefreshRecordings = ReactiveCommand.Create();
            CmdRefreshRecordings.Subscribe(_ =>
            {
            });
            DisposableRxElements.Add(CmdRefreshRecordings);

            CmdDeleteSelectedRecording = ReactiveCommand.Create(m_SelectedRecordingBehaviorSubject.Select(rec => rec != null));
            CmdDeleteSelectedRecording.Subscribe(async _ =>
            {
                await DeleteSelectedRecording();
            });
            DisposableRxElements.Add(CmdDeleteSelectedRecording);

            CmdViewSelectedRecording = ReactiveCommand.Create(m_SelectedRecordingBehaviorSubject.Select(rec => rec != null));
            DisposableRxElements.Add(CmdViewSelectedRecording);
        }

        private async Task DeleteSelectedRecording()
        {
            if (SelectedRecording == null)
                return;

            bool success = await OperationAdapter.DeleteRecording(SelectedRecording.Id);
            if (!success)
            {
                MessageBox.Show(string.Format("Error deleting record '{0}'", SelectedRecording));
            }
        }

        private void FillRecordingBufferWithCurrentValues()
        {
            foreach (IRecording recording in OperationAdapter.RecordingCollection)
            {
                RecordingsObservableCollection.Add(recording);
            }
        }

        private void FillRibbonCommands()
        {
            InsertRibbonButton(Resources.RibbonTab_ManageRecordings, Resources.RibbonGroup_ManageRecordings, Resources.RibbonElement_PlayRecording, Resources.media_playback_start_7_32.ToBitmapImage(), CmdViewSelectedRecording);
            InsertRibbonButton(Resources.RibbonTab_ManageRecordings, Resources.RibbonGroup_ManageRecordings, Resources.RibbonElement_DeleteRecording, Resources.edit_delete_9_32.ToBitmapImage(), CmdDeleteSelectedRecording);
            InsertRibbonButton(Resources.RibbonTab_ManageRecordings, Resources.RibbonGroup_ManageRecordings, Resources.RibbonElement_RefreshRecordings, Resources.view_refresh_5_32.ToBitmapImage(), CmdRefreshRecordings);
        }

        private void RemoveRecordingsToDisplayBuffer(IList items)
        {
            foreach (IRecording recording in items.Cast<IRecording>().Where(recording => recording != null))
            {
                RecordingsObservableCollection.Remove(recording);
            }
        }
    }
}